#include "dkglGrid.h"
#include "dkglPreRequest.h"

namespace DKGL
{
    namespace primitive
    {
        Grid::Grid(const String& name, float width, float height, int width_segs, int height_segs):
            Mesh(name),
            _width(width),
            _height(height),
            _width_segments(width_segs),
            _height_segments(height_segs),
            _indexBuf(NULL)
        {
            //TODO check argument
            allocBuf();
            initVertexBuf();
            initIndexBuf();
            genDisplayList();
        }


        Grid::~Grid()
        {
            if (_indexBuf)
                delete [] _indexBuf;

            if(_displayListId)
                glDeleteLists(_displayListId, 1);
        }


		void Grid::setMaterial(int, MaterialPtr matPtr)
		{
			_materialPtr = matPtr;
		}


        void Grid::allocBuf()
        {
            vertexBuf.alloc(
                (_width_segments+1)*(_height_segments+1));

            _indexBuf = new unsigned int[2*(_width_segments+1)*_height_segments];
        }

        void Grid::initVertexBuf()
        {
            float step_x = _width / _width_segments;
            float step_y = _height / _height_segments;
            float xshift = _width / 2;
            float yshift = _height / 2;
            float x, y;
            int base, index;

	        for(int j=0;j<_height_segments+1;j++)
	        {
                base = j*(_width_segments+1);
		        for(int i=0;i<_width_segments+1;i++)
		        {
			        index = base + i;
                    x = step_x*i - xshift;
                    y = step_y*j - yshift;
                    vertexBuf.set(index, x, y, 0.0f);
		        }
	        }
        }

        void Grid::initIndexBuf()
        {
            int curline;
            int nextline;
            int index = 0;

            for (int h=0;h<_height_segments;h++)
            {
                curline = h*(_width_segments+1);
                nextline = (h+1)*(_width_segments+1);
                
                for (int w=0;w<_width_segments+1;w++)
                {
                    _indexBuf[index] = curline + w;
                    index++;
                    _indexBuf[index] = nextline + w;
                    index++;
                }
            }
        }

        void Grid::genDisplayList()
        {
            _displayListId = glGenLists(1);
	        if(!_displayListId) 
                assert(0);

	        glEnableClientState(GL_VERTEX_ARRAY);     
	        glVertexPointer(3, GL_FLOAT, 0, vertexBuf.get());
            
            glNewList(_displayListId, GL_COMPILE);
            {
				int offset = (_width_segments+1)*2;
                for (int i = 0;i<_height_segments;i++)
                {
                    glDrawElements(
                        GL_QUAD_STRIP,
                        offset,
                        GL_UNSIGNED_INT,
                        _indexBuf + i*offset);
                }
            }
            glEndList();
	        glDisableClientState(GL_VERTEX_ARRAY);
        }


        void Grid::renderImpl()
        {
			Mesh::renderImpl();
			_materialPtr->begin();
            glCallList(_displayListId);
        }
    }
}